package com.such.kit.io.helper;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.such.kit.easyparam.ParamMap;
import com.such.kit.io.bean.XmlTemplateItemConfig;
import com.such.kit.io.source.MemoryIOSource;
import com.such.kit.validate.ValidateCommons;

public class XmlTemplateHelper {

	/**
	 * <pre>
	 * 解析 {@link MemoryIOSource#inputResult} 数据
	 * 将平面数据转换为结构化数据
	 * </pre>
	 * @param ioSource 数据源
	 * @param rootItemConfig 模板根配置项
	 * @param rootItemParams 模板根表达式参数
	 * @return 构化数据
	 */
	public static Map<String, Object> parseInputResult(MemoryIOSource ioSource, XmlTemplateItemConfig rootItemConfig, Map<String, Object> rootItemParams) throws Exception {
		if (ValidateCommons.isNotEmpty(rootItemConfig)) {
			String expression = rootItemConfig.getExpression();
			String key = rootItemConfig.getKey();
			String type = rootItemConfig.getType();
			List<Map<String, Object>> planeDatas = ioSource.getInputResult(expression, rootItemParams);
			if (ValidateCommons.isNotEmpty(planeDatas)) {
				if (XmlTemplateItemConfig.TYPE_OBJECT.equals(type)) {
					Map<String, Object> planeData = planeDatas.get(0);
					converter(rootItemConfig, planeData);
					parseInputResultHelper(ioSource, rootItemConfig.getSubItemConfigs(), planeData, null);
					if (ValidateCommons.isNotEmpty(key)) {
						return new ParamMap<String, Object>().putParam(key, planeData);
					} else {
						return planeData;
					}
				} else if (XmlTemplateItemConfig.TYPE_ARRAY.equals(type)) {
					throw new Exception("xml 根项 type 默认且必须为 object");
				}
			}
		}
		return null;
	}

	private static void parseInputResultHelper(MemoryIOSource ioSource, List<XmlTemplateItemConfig> itemConfigs,
			Map<String, Object> data, Map<String, Object> upperData) throws Exception {
		if (ValidateCommons.isNotEmpty(itemConfigs)) {
			if (ValidateCommons.isEmpty(upperData)) {
				upperData = new HashMap<String, Object>();
			}
			for (XmlTemplateItemConfig itemConfig : itemConfigs) {
				String expression = itemConfig.getExpression();
				String key = itemConfig.getKey();
				String type = itemConfig.getType();
				List<XmlTemplateItemConfig> subItemConfigs = itemConfig.getSubItemConfigs();
				List<Map<String, Object>> planeDatas = ioSource.getInputResult(expression, upperData);
				if (ValidateCommons.isNotEmpty(planeDatas)) {
					if (XmlTemplateItemConfig.TYPE_OBJECT.equals(type)) {
						Map<String, Object> planeData = planeDatas.get(0);
						upperData.putAll(planeData);
						parseInputResultHelper(ioSource, subItemConfigs, planeData, upperData);
						converter(itemConfig, planeData);
						if (ValidateCommons.isNotEmpty(key)) {
							data.put(key, planeData);
						} else {
							data.putAll(planeData);
						}
					} else if (XmlTemplateItemConfig.TYPE_ARRAY.equals(type)) {
						for (Map<String, Object> planeData : planeDatas) {
							upperData.putAll(planeData);
							parseInputResultHelper(ioSource, subItemConfigs, planeData, upperData);
							converter(itemConfig, planeData);
						}
						if (ValidateCommons.isNotEmpty(key)) {
							data.put(key, planeDatas);
						} else {
							throw new Exception("入参或返回值的类型为 array 时 key 不能为空");
						}
					}
				}
			}
		}
	}

	/**
	 * <pre>
	 * 构建 {@link MemoryIOSource#outputResult} 数据
	 * 将结构化数据转换为平面数据
	 * </pre>
	 * @param ioSource 数据源
	 * @param rootItemConfig 模板根配置项
	 * @param rootItemParams 模板根表达式参数
	 * @param data 结构化数据
	 */
	public static void buildOutputResult(MemoryIOSource ioSource, XmlTemplateItemConfig rootItemConfig, Map<String, Object> rootItemParams,
			Map<String, Object> data) throws Exception {
		if (ValidateCommons.isNotEmpty(rootItemConfig) && ValidateCommons.isNotEmpty(data)) {
			String expression = rootItemConfig.getExpression();
			String key = rootItemConfig.getKey();
			String type = rootItemConfig.getType();
			if (XmlTemplateItemConfig.TYPE_OBJECT.equals(type)) {
				Map<String, Object> planeData = null;
				if (ValidateCommons.isNotEmpty(key)) {
					planeData = ParamMap.getValue(key, data, new HashMap<String, Object>());
				} else {
					planeData = data;
				}
				converter(rootItemConfig, planeData);
				ioSource.setOutputResult(expression, rootItemParams, planeData);
				buildOutputResultHelper(ioSource, rootItemConfig.getSubItemConfigs(), planeData, planeData);
			} else if (XmlTemplateItemConfig.TYPE_ARRAY.equals(type)) {
				throw new Exception("xml 根项 type 默认且必须为 object");
			}
		}
	}

	private static void buildOutputResultHelper(MemoryIOSource ioSource, List<XmlTemplateItemConfig> itemConfigs,
			Map<String, Object> data, Map<String, Object> upperData) throws Exception {
		if (ValidateCommons.isNotEmpty(itemConfigs) && ValidateCommons.isNotEmpty(data)) {
			if (ValidateCommons.isEmpty(upperData)) {
				upperData = new HashMap<String, Object>();
			}
			for (XmlTemplateItemConfig itemConfig : itemConfigs) {
				String expression = itemConfig.getExpression();
				String key = itemConfig.getKey();
				String type = itemConfig.getType();
				if (XmlTemplateItemConfig.TYPE_OBJECT.equals(type)) {
					Map<String, Object> planeData = null;
					if (ValidateCommons.isNotEmpty(key)) {
						planeData = ParamMap.getValue(key, data, new HashMap<String, Object>());
					} else {
						planeData = data;
					}
					converter(itemConfig, planeData);
					ioSource.setOutputResult(expression, upperData, planeData);
					upperData.putAll(planeData);
					buildOutputResultHelper(ioSource, itemConfig.getSubItemConfigs(), planeData, upperData);
				} else if (XmlTemplateItemConfig.TYPE_ARRAY.equals(type)) {
					if (ValidateCommons.isNotEmpty(key)) {
						List<Map<String, Object>> planeDatas = ParamMap.getValue(key, data);
						if (ValidateCommons.isNotEmpty(planeDatas)) {
							for (Map<String, Object> planeData : planeDatas) {
								converter(itemConfig, planeData);
								ioSource.setOutputResult(expression, upperData, planeData);
								upperData.putAll(planeData);
								buildOutputResultHelper(ioSource, itemConfig.getSubItemConfigs(), planeData, upperData);
							}
						}
					} else {
						throw new Exception("入参或返回值的类型为 array 时 key 不能为空");
					}
				}
			}
		}
	}

	/**
	 * <pre>
	 * 转换数据中的键
	 * </pre>
	 * @param itemConfig 配置项
	 * @param data 数据
	 */
	private static void converter(XmlTemplateItemConfig itemConfig, Map<String, Object> data) {
		if (ValidateCommons.isNotEmpty(itemConfig) && ValidateCommons.isNotEmpty(data)) {
			Map<String, String> converter = itemConfig.getConverter();
			if (ValidateCommons.isNotEmpty(converter)) {
				for (String key : converter.keySet()) {
					Object value = data.remove(key);
					if (ValidateCommons.isNotEmpty(value)) {
						data.put(itemConfig.convert(key), value);
					}
				}
			}
		}
	}

}
